package org.misalen.web.admin.shiro;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.shiro.config.Ini;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.util.AntPathMatcher;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.util.PatternMatcher;
import org.apache.shiro.web.config.IniFilterChainResolverFactory;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.misalen.web.database.repository.mysql.SysResourcesRepository;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 自定义shiro工厂 动态赋权限 刷新权限
 * 
 * @author guochao
 *
 */
public class ShiroPermissionFactory extends ShiroFilterFactoryBean implements ShiroChainDefinitionsService {
	@Autowired
	protected SysResourcesRepository sysResourcesRepository;

	private String definitions;

	private PatternMatcher pathMatcher = new AntPathMatcher();
	private static final Logger LOGGER = LogManager.getLogger(ShiroDbRealm.class);

	@Override
	public void setFilterChainDefinitions(String definitions) {
		this.definitions = definitions;
		intiPermission();
	}

	@Override
	public void intiPermission() {
		LOGGER.info("Shiro初始化全部表达式地址");
		Ini ini = new Ini();
		ini.load(definitions);
		Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
		if (CollectionUtils.isEmpty(section)) {
			section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
		}
		Map<String, String> otherChains = initOtherPermission();
		section.putAll(otherChains);
		setFilterChainDefinitionMap(section);
	}

	@Override
	public synchronized void updatePermission() throws Exception {
		LOGGER.info("Shiro更新全部表达式地址");
		AbstractShiroFilter shiroFilter = (AbstractShiroFilter) getObject();
		PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter
				.getFilterChainResolver();
		DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
		// 清空权限管理资源 重新设置
		manager.getFilterChains().clear();
		getFilterChainDefinitionMap().clear();
		intiPermission();
		Map<String, String> chains = getFilterChainDefinitionMap();
		for (Map.Entry<String, String> entry : chains.entrySet()) {
			String url = entry.getKey();
			String chainDefinition = entry.getValue().trim().replace(" ", "");
			manager.createChain(url, chainDefinition);
		}
	}

	@Override
	public Map<String, String> initOtherPermission() {
		Map<String, String> otherChains = new HashMap<String, String>();
		List<Map<String, Object>> maps = sysResourcesRepository.findResources();
		for (Map<String, Object> map : maps) {
			if (map.containsKey("url")) {
				String[] expressions = String.valueOf(map.containsKey("url")).split(",");
				String roles = String.valueOf(map.get("code"));
				for (String expression : expressions) {
					otherChains.put(expression, roles);
				}
			}
		}
		return dealWithExpression(otherChains);
	}

	@Override
	public Map<String, String> dealWithExpression(Map<String, String> map) {
		for (Entry<String, String> entry : map.entrySet()) {
			String expression = entry.getKey();
			String roles = entry.getValue();
			for (Entry<String, String> entry2 : map.entrySet()) {
				String expression2 = entry2.getKey();
				String roles2 = entry2.getValue();
				if (!expression.equals(expression2) && pathMatcher.matches(expression, expression2)) {
					map.put(expression2, roles + "," + roles2);
				}
			}
		}
		Map<String, String> otherChains = new HashMap<String, String>();
		for (Entry<String, String> entry : map.entrySet()) {
			otherChains.put(entry.getKey(), String.format(PORPERMS_STRING, entry.getValue()));
		}
		if (LOGGER.isDebugEnabled()) {
			for (Entry<String, String> entry : otherChains.entrySet()) {
				LOGGER.debug(entry.getKey() + "\t" + entry.getValue());
			}
		}
		return otherChains;
	}
}
